package com.kate.mall.bff.wx.service;

import cn.hutool.core.map.MapUtil;
import com.kate.mall.bff.wx.feign.ProductFeignClient;
import com.kate.mall.bff.wx.pool.ThreadPoolUtils;
import com.kate.mall.bff.wx.vo.brand.HomeBrandVO;
import com.kate.mall.bff.wx.vo.goods.HomeHotGoodsVo;
import com.kate.mall.bff.wx.vo.goods.HomeNewsGoodsVo;
import com.kate.mall.common.exception.NDException;
import com.kate.mall.common.utils.ListMap2ListVoUtils;
import com.kate.mall.common.utils.ListMap2VoUtil;
import com.kate.mall.common.utils.R;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * @author 新梦想.陈超
 * @version 2021.2
 * @Description: {TODO}
 * @date 2023/3/6 下午2:38
 */

@Service
@Slf4j
public class HomeIndexService {

    @Resource
    private ListMap2VoUtil listMap2VoUtil;
    @Resource
    private ProductFeignClient productFeignClient;

    /**
     * @Cacheable  作用就是将方法的返回值，以指定key的方式保存redis中，以后再调用该方法，先从redis中查询数据
     *             如果有，则直接返回，如果没有，则执行当前方法，远程调用，进行数据库的查询
     *cacheNames   缓存名
     *key：        缓存键
     *unless       指定方法返回值满足条件，则不缓存
     * #result['data']?.size()  就是方法返回值的data为key,对应的value的size为0 ，则不缓存返回值
     * @return
     */
    @Cacheable(cacheNames = "wx-bff",key = "'h:i'",unless="#result['data']?.size()==0")
    public R index() {
        //1.定义结果map集合和参数map集合
        Map resultMap = new HashMap();
        Map paramMap = new HashMap();
        //TODO 1.banner 轮播图 limit=3 【ndmall_sms 营销库】

        //TODO 2.brandList 品牌列表        limit=4【ndmall_pms 商品库】
        paramMap.clear();
        paramMap.put("limit", 4);
        R brandListR = productFeignClient.brandList(paramMap);
        //从brandListR取出品牌列表数据--hutool工具包
        List<Map> brandListMap = MapUtil.get((Map) brandListR.get("page"), "list", List.class);
        //工具类VO:view Object视图对象 ，返回客户端的对象----List<Map>===>List<VO>
        List<HomeBrandVO> brandVOList = listMap2VoUtil.<HomeBrandVO>map2vo(brandListMap, HomeBrandVO.class);

        resultMap.put("brandList", brandVOList);
        //TODO 3.channel 商品分类 limit=9 【ndmall_pms】
        //TODO 4.floorGoodsList 楼层商品列表 limit=4【ndmall_pms】
        //TODO 5.hotGoodsList 热卖推荐 limit=6【ndmall_pms】
        paramMap.clear();
        paramMap.put("limit", 6);
        paramMap.put("isHot", 1);
        R hotGoodsListR = productFeignClient.hotGoodsList(paramMap);
        //从brandListR取出品牌列表数据--hutool工具包
        List<Map> hotGoodsListMap = MapUtil.get((Map) hotGoodsListR.get("page"), "list", List.class);
        //工具类VO:view Object视图对象 ，返回客户端的对象----List<Map>===>List<VO>
        List<HomeHotGoodsVo> hotGoodsVOList = listMap2VoUtil.<HomeHotGoodsVo>map2vo(hotGoodsListMap, HomeHotGoodsVo.class);
        resultMap.put("hotGoodsList", hotGoodsVOList);
        //TODO 6.newGoodsList 新品推荐 limit=6【ndmall_pms】

        paramMap.clear();
        paramMap.put("limit", 6);
        paramMap.put("isNew", 1);
        R newGoodsListR = productFeignClient.newGoodsList(paramMap);
        List<Map> newGoodsListMap = MapUtil.get((Map) newGoodsListR.get("page"), "list", List.class);
        //工具类VO:view Object视图对象 ，返回客户端的对象----List<Map>===>List<VO>
        List<HomeNewsGoodsVo> newGoodsVOList = listMap2VoUtil.<HomeNewsGoodsVo>map2vo(newGoodsListMap, HomeNewsGoodsVo.class);
        resultMap.put("newGoodsList", newGoodsVOList);
        //TODO 7.grouponList 团购专区        【limit=2 【ndmall_sms】
        //TODO 8.topicList 主题精选 limit=4 【ndmall_mms商城库】
        //TODO 9.couponList 优惠券 limit=2 【ndmall_sms营销库】
        return R.ok().put("data", resultMap);
    }
    /**
     * @Cacheable  作用就是将方法的返回值，以指定key的方式保存redis中，以后再调用该方法，先从redis中查询数据
     *             如果有，则直接返回，如果没有，则执行当前方法，远程调用，进行数据库的查询
     *cacheNames   缓存名
     *key：        缓存键
     *unless       指定方法返回值满足条件，则不缓存
     * #result['data']?.size()  就是方法返回值的data为key,对应的value的size为0 ，则不缓存返回值
     * @return
     */
    @Cacheable(cacheNames = "wx-bff",key = "'h:i'",unless="#result['data']?.size()==0")
    public R index2() {
        log.info("===========home index从【数据库】查询数据=========");
        //1.定义结果map集合和参数map集合
        Map resultMap = new HashMap();

        ThreadPoolExecutor pool = ThreadPoolUtils.instance(true);
        try {
            //TODO 1.banner 轮播图 limit=3 【ndmall_sms 营销库】
            //TODO 2.brandList 品牌列表        limit=4【ndmall_pms 商品库】
            Future<R> brandListRFuture = pool.submit(()->
                     productFeignClient.brandList(generatorParams(
                            new String[]{"limit"},
                            new Object[]{"4"}))
            );
            //TODO 3.channel 商品分类 limit=9 【ndmall_pms】
            //TODO 4.floorGoodsList 楼层商品列表 limit=4【ndmall_pms】
            //TODO 5.hotGoodsList 热卖推荐 limit=6【ndmall_pms】
            Future<R> hotGoodsListRFuture = pool.submit(() ->
                    productFeignClient.hotGoodsList(generatorParams(
                        new String[]{"limit","isHot"},
                        new Object[]{"6","1"}))
            );
            //TODO 6.newGoodsList 新品推荐 limit=6【ndmall_pms】
            Future<R> newGoodsListRFuture = pool.submit(() ->
                    productFeignClient.hotGoodsList(generatorParams(
                        new String[]{"limit","isNew"},
                        new Object[]{"6","1"}))
            );
            //TODO 7.grouponList 团购专区        【limit=2 【ndmall_sms】
            //TODO 8.topicList 主题精选 limit=4 【ndmall_mms商城库】
            //TODO 9.couponList 优惠券 limit=2 【ndmall_sms营销库】
            parseFuture(brandListRFuture, resultMap, "brandList", HomeBrandVO.class);
            parseFuture(hotGoodsListRFuture, resultMap, "hotGoodsList", HomeHotGoodsVo.class);
            parseFuture(newGoodsListRFuture, resultMap, "newGoodsList", HomeNewsGoodsVo.class);
        } finally {
            pool.shutdown();
        }
        return R.ok().put("data", resultMap);
    }
    public R index3() {
        //1.定义结果map集合和参数map集合
        Map resultMap = new HashMap();

        ThreadPoolExecutor pool = ThreadPoolUtils.instance(true);
        try {
            //TODO 1.banner 轮播图 limit=3 【ndmall_sms 营销库】

            //TODO 2.brandList 品牌列表        limit=4【ndmall_pms 商品库】
            CompletableFuture<R> brandListRFuture= CompletableFuture.supplyAsync(()->{
                return productFeignClient.brandList(generatorParams(
                        new String[]{"limit"},
                        new Object[]{"4"}));
            },pool);
            //TODO 3.channel 商品分类 limit=9 【ndmall_pms】
            //TODO 4.floorGoodsList 楼层商品列表 limit=4【ndmall_pms】
            //TODO 5.hotGoodsList 热卖推荐 limit=6【ndmall_pms】
            CompletableFuture<R> hotGoodsListRFuture= CompletableFuture.supplyAsync(()->{
                return productFeignClient.hotGoodsList(generatorParams(
                        new String[]{"limit","isHot"},
                        new Object[]{"6","1"}));
            },pool);
            //TODO 6.newGoodsList 新品推荐 limit=6【ndmall_pms】
            CompletableFuture<R> newGoodsListRFuture= CompletableFuture.supplyAsync(()->{
                return productFeignClient.hotGoodsList(generatorParams(
                        new String[]{"limit","isNew"},
                        new Object[]{"6","1"}));
            },pool);
            //TODO 7.grouponList 团购专区        【limit=2 【ndmall_sms】
            //TODO 8.topicList 主题精选 limit=4 【ndmall_mms商城库】
            //TODO 9.couponList 优惠券 limit=2 【ndmall_sms营销库】
            parseFuture(brandListRFuture, resultMap, "brandList", HomeBrandVO.class);
            parseFuture(hotGoodsListRFuture, resultMap, "hotGoodsList", HomeHotGoodsVo.class);
            parseFuture(newGoodsListRFuture, resultMap, "newGoodsList", HomeNewsGoodsVo.class);
        } finally {
            pool.shutdown();
        }
        return R.ok().put("data", resultMap);
    }

    /**
     * 解析异步调用Futrue<R>，并转换为VO,最后填充到resultMap结果集中
     * @param future    异步调用Future
     * @param resultMap 结果集
     * @param responseKey 响应的key
     * @param voClazz       Vo的class
     */
    private <T> void  parseFuture(Future<R> future, Map resultMap, String responseKey, Class<T> voClazz)  {
        R listR = null;
        try {
            listR = future.get();
        } catch (Exception e) {
            throw new NDException("首页接口请求数据异常....");
        }
        List<Map> newGoodsMapList = MapUtil.get(MapUtil.get(listR, "page", Map.class), "list", List.class);
        //裁剪字段两种方案：一、自己写工具类(框架)  二 、mapStruct框架
        //List<map>====>list<vo>
        List VoList = listMap2VoUtil.<T>map2vo(newGoodsMapList, voClazz);
        resultMap.put(responseKey, VoList);
    }
    /**
     * 构建远程调用参数map
     *
     * @param keys   参数key
     * @param values 参数value
     * @return
     */
    public Map<String, Object> generatorParams(String[] keys, Object[] values) {
        ConcurrentHashMap<String, Object> params = MapUtil.newConcurrentHashMap();//线程安全HashMap
        if (keys.length != values.length) {
            throw new RuntimeException("键值数量不匹配，参数错误");
        }
        for (int i = 0; i < keys.length; i++) {
            params.put(keys[i], values[i]);
        }
        return params;
    }
}
